package com.kedacom.ctsp.authority.service.simple;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.kedacom.ctsp.authority.dto.DataAccessDTO;
import com.kedacom.ctsp.authority.entity.Resource;
import com.kedacom.ctsp.authority.entity.ResourceSettingRelation;
import com.kedacom.ctsp.authority.entity.SettingForType;
import com.kedacom.ctsp.authority.service.ResourceSettingRelationService;
import com.kedacom.ctsp.authority.vo.ResourceSettingRelationBatchVO;
import com.kedacom.ctsp.authority.vo.ResourceSettingRelationVO;
import com.kedacom.ctsp.authz.access.DataAccessScopeEnum;
import com.kedacom.ctsp.authz.entity.AuthResource;
import com.kedacom.ctsp.authz.entity.ResourceEnum;
import com.kedacom.ctsp.lang.EnumUtil;
import com.kedacom.ctsp.lang.mapper.BeanMapper;
import com.kedacom.ctsp.orm.param.Term;
import com.kedacom.ctsp.orm.param.TermEnum;
import com.kedacom.ctsp.web.service.CrudService;
import com.kedacom.ctsp.web.service.StatusEnum;
import com.kedacom.ctsp.web.service.simple.AbstractCrudEntityService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.kedacom.ctsp.authority.entity.SettingForType.*;

/**
 * @author sunchenjie
 * @date 2017/11/12
 */
@Service("authorityResourceSettingService")
@Slf4j
public class ResourceSettingRelationServiceImpl
        extends AbstractCrudEntityService<ResourceSettingRelation, String>
        implements ResourceSettingRelationService, CrudService<ResourceSettingRelation, String> {

    @Override
    public String insert(ResourceSettingRelation entity) {

        //TODO 鉴权防止添加超出自身的权限

        if (entity.getStatus() == null) {
            entity.setStatus(StatusEnum.ENABLE.ordinal());
        }
        return super.insert(entity);
    }

    @Override
    public int delete(List<String> ids) {
        if (CollectionUtils.isNotEmpty(ids)) {
            return createDelete().in(ResourceSettingRelation.ID, ids).exec();
        }
        return 0;
    }

    @Override
    public void deleteBySettingFor(SettingForType settingForType, String settingForId) {
        createDelete().where(ResourceSettingRelation.SETTING_FOR_TYPE, settingForType).and(ResourceSettingRelation.SETTING_FOR_ID, settingForId).exec();
    }

    @Override
    public void deleteBySettingFor(SettingForType settingForType, String settingForId, List<String> resourceIds) {
        logger.info("删除源资源 resourceIds [{}] , settingForType [{}] , settingForId [{}]", resourceIds.toString(),
                settingForType.ordinal(), settingForId);
        if (CollectionUtils.isEmpty(resourceIds)) {
            return;
        }
        createDelete()
                .where(ResourceSettingRelation.SETTING_FOR_TYPE, settingForType)
                .and(ResourceSettingRelation.SETTING_FOR_ID, settingForId)
                .in(ResourceSettingRelation.RESOURCE_ID, resourceIds)
                .exec();
    }

    /**
     * @param userId
     * @return 用户配置的资源
     */
    @Override
    public Set<AuthResource> getAuthResourcesByUser(String userId, ResourceEnum source) {
        // user上的resource
        List<ResourceSettingRelation> userRes = createQuery().where()
                .is(ResourceSettingRelation.SETTING_FOR_TYPE, USER)
                .is(ResourceSettingRelation.SETTING_FOR_ID, userId)
                .is(ResourceSettingRelation.STATUS, StatusEnum.ENABLE.ordinal())
                .listNoPaging();

        if (CollectionUtils.isNotEmpty(userRes)) {
            return convertResources(userRes, source);
        }
        return Sets.newHashSet();
    }

    /**
     * 加载用户所拥有的资源
     *
     * @param uid
     * @param deptId
     * @return 用户拥有的资源
     */
    @Override
    public Set<AuthResource> getAuthResourcesByRoles(String uid, String deptId, Set<String> roleIds, ResourceEnum resourceEnum) {

        log.info("initUserResources userId:[{}]", uid);

        Set<AuthResource> resources = Sets.newHashSet();

        //用户资源
        Set<AuthResource> userResources = getAuthResourcesByUser(uid, resourceEnum);
        log.info("用户资源: " + userResources.size());
        resources.addAll(userResources);

        //角色资源
        if (CollectionUtils.isNotEmpty(roleIds)) {
            Set<AuthResource> roleResources = getAuthResourcesByRoles(roleIds, resourceEnum);
            log.info("角色资源: " + roleResources.size());
            resources.addAll(roleResources);
        }
        // 部门资源
        if (deptId != null) {
            Set<AuthResource> deptResources = getAuthResourcesByDid(deptId, resourceEnum);
            log.info("部门资源: " + deptResources.size());
            resources.addAll(deptResources);
        }
        return resources;
    }

    /**
     * @param deptId
     * @return 用户所在部门的资源
     */
    @Override
    public Set<AuthResource> getAuthResourcesByDid(String deptId, ResourceEnum configSource) {
        // 状态是1（启用状态）
        List<ResourceSettingRelation> rss = createQuery().where().is(
                ResourceSettingRelation.SETTING_FOR_TYPE, DEPARTMENT
        ).is(ResourceSettingRelation.SETTING_FOR_ID, deptId)
                .is(ResourceSettingRelation.STATUS, StatusEnum.ENABLE.ordinal())
                .listNoPaging();

        if (CollectionUtils.isNotEmpty(rss)) {
            return convertResources(rss, configSource);
        }
        return Sets.newHashSet();
    }

    /**
     * @param deptIds
     * @return 用户所在部门的资源
     */
    @Override
    public Set<AuthResource> getAuthResourcesByDids(Set<String> deptIds, ResourceEnum configSource) {
        // 状态是1（启用状态）
        List<ResourceSettingRelation> rss = createQuery().where()
                .is(ResourceSettingRelation.SETTING_FOR_TYPE, DEPARTMENT)
                .in(ResourceSettingRelation.SETTING_FOR_ID, deptIds)
                .is(ResourceSettingRelation.STATUS, StatusEnum.ENABLE.ordinal())
                .listNoPaging();

        if (CollectionUtils.isNotEmpty(rss)) {
            return convertResources(rss, configSource);
        }
        return Sets.newHashSet();
    }

    /**
     * @param roleIds
     * @return 用户对应角色的资源
     */
    @Override
    public Set<AuthResource> getAuthResourcesByRoles(Set<String> roleIds, ResourceEnum configSource) {
        List<ResourceSettingRelation> resourceSRs = createQuery().where()
                .is(ResourceSettingRelation.SETTING_FOR_TYPE, ROLE)
                .in(ResourceSettingRelation.SETTING_FOR_ID, roleIds)
                .is(ResourceSettingRelation.STATUS, StatusEnum.ENABLE.ordinal())
                .listNoPaging();

        if (CollectionUtils.isNotEmpty(resourceSRs)) {
            return convertResources(resourceSRs, configSource);
        }
        return Sets.newHashSet();
    }

    private ResourceSettingRelation createSettingEntity(ResourceSettingRelationBatchVO data, ResourceSettingRelationVO settingVO, Resource r) {
        // 复制 remark,creator等
        ResourceSettingRelation entity = BeanMapper.deepMap(data, ResourceSettingRelation.class);
        // 复制settingForType、id
        entity.setSettingForType(settingVO.getSettingForType());
        entity.setSettingForId(settingVO.getSettingForId());
        // 复制resourceId,sign,type
        entity.setResource(r);

        return entity;
    }


    @Override
    public List<String> batchMerge(SettingForType settingForType, String settingForId, List<ResourceSettingRelation> rss) {
        // 先删除
        deleteBySettingFor(settingForType, settingForId);
        return batchAdd(settingForType, settingForId, rss);
    }

    @Override
    public List<String> batchAdd(SettingForType settingForType, String settingForId, List<ResourceSettingRelation> rss) {
        // 先删除指定资源,而不是所有的资源
        List<String> resourceIds = new ArrayList<>();

        rss.forEach(r -> {
            if (r.getResource() != null && r.getResource().getId() != null) {
                resourceIds.add(r.getResource().getId());
            }
        });

        deleteBySettingFor(settingForType, settingForId, resourceIds);
        // 再添加
        List<String> ids = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(rss)) {
            for (ResourceSettingRelation rs : rss) {
                rs.setSettingForType(settingForType);
                rs.setSettingForId(settingForId);
                String id = insert(rs);
                ids.add(id);
            }
        }
        return ids;
    }

    @Override
    public String merge(ResourceSettingRelation entity) {
        List<ResourceSettingRelation> result;
        //从 Setting type+id 维度
        if (entity.getId() == null) {
            result = createQuery().where(ResourceSettingRelation.RESOURCE_ID, entity.getResource().getId())
                    .is(ResourceSettingRelation.SETTING_FOR_TYPE, entity.getSettingForType())
                    .is(ResourceSettingRelation.SETTING_FOR_ID, entity.getSettingForId()).listNoPaging();
        }
        //从id维度
        else {
            result = Arrays.asList(get(entity.getId()));
        }
        // 数量==1 更新
        if (CollectionUtils.isNotEmpty(result) && result.size() == 1) {
            update(result.get(0).getId(), entity);
            return entity.getId();
        } else {
            //数量>1 删除原有的
            if (CollectionUtils.isNotEmpty(result)) {
                List<String> collect = result.stream().map(ResourceSettingRelation::getId).collect(Collectors.toList());
                delete(collect);
            }
            return insert(entity);
        }
    }

    /**
     * 把ResourceSetting转换为 AuthResource
     *
     * @param resourceSettings
     * @param source
     * @return
     */
    @Override
    public Set<AuthResource> convertResources(List<ResourceSettingRelation> resourceSettings, ResourceEnum source) {
        if (CollectionUtils.isNotEmpty(resourceSettings)) {
            Set<AuthResource> authResources = resourceSettings.stream().map(
                    rs -> {
                        AuthResource ar = new AuthResource();
                        ar.setConfigSource(source);

                        // 对应的resource
                        Resource r = rs.getResource();
                        if (r != null) {
                            ar.setSign(r.getSign());
                            ar.setType(r.getType());
                            ar.setId(r.getId());
                            ar.setName(r.getName());
                            ar.setUrl(r.getUrl());
                            ar.setMethod(r.getMethod());
                        }

                        ResourceSettingRelationVO detailVo = BeanMapper.newInstanceSilently(ResourceSettingRelationVO.class).convertFrom(rs);

                        // field 字段名数组
                        ar.setIncludeFields(detailVo.getIncludeFields());
                        ar.setExcludeFields(detailVo.getExcludeFields());

                        // dataScope 枚举 （4种）
                        String dataScope = detailVo.getDataScope();
                        ar.setDataScope(DataAccessScopeEnum.parse(dataScope));

                        // 自定义DataAccess查询 Term
                        List<DataAccessDTO> dataAccess = detailVo.getDataAccess();
                        if (null != dataAccess) {
                            List<Term> terms = dataAccess.stream().map(
                                    da -> {
                                        Term term = new Term();
                                        term.setValue(da.getValue());
                                        term.setColumn(da.getColumn());
                                        term.setTermType(EnumUtil.parse(da.getTerm(), TermEnum.class));
                                        return term;
                                    }
                            ).collect(Collectors.toList());
                            ar.setDataAccess(terms);
                        }
                        return ar;
                    }
            ).collect(Collectors.toSet());

            return authResources;
        }
        return Sets.newHashSet();
    }
}

